﻿using System;
using System.Text;
using System.Xml.Linq;
using DataGeneration.Domain.Helpers;

namespace DataGeneration.Domain.CustomProcessors
{
    public class NonKeyColumnProcessor
    {
        /// <summary>
        /// Appends the non key property value.
        /// </summary>
        /// <param name="propertyValues">The property values.</param>
        /// <param name="property">The property.</param>
        /// <param name="tableName">Name of the table.</param>
        /// <param name="entityKeyFilename">The entity key filename.</param>
        /// <param name="dataAccess">The data access.</param>
        /// <param name="currentIteration">The current iteration.</param>
        public static void AppendNonKeyPropertyValue(StringBuilder propertyValues, XElement property, string tableName, string entityKeyFilename, DataAccessLayer.DataAccess dataAccess, int currentIteration)
        {
            propertyValues.AppendFormat("{0},", GeneratePropertyValue(property, tableName, entityKeyFilename, dataAccess,currentIteration));
        }


        private static string GeneratePropertyValue(XElement property, string tableName, string entityKeyFilename, DataAccessLayer.DataAccess dataAccess, int currentIteration)
        {
            string returnValue;

            if (property.ContainsAttributeWithoutValue(Tokens.ActualValue, ""))
            {
                returnValue = property.ReadAttributeValue(Tokens.ActualValue);
            }
            else
            {
                string hintValue = "";
                if (property.ContainsAttribute(Tokens.Hint))
                {
                    hintValue = property.ReadAttributeValue(Tokens.Hint);
                }
                switch (property.ReadAttributeValue(Tokens.Type).Trim().ToLower())
                {
                    case "guid":
                        returnValue = string.Format("'{0}'",  Guid.NewGuid());
                        break;
                    case "bit":
                        returnValue = RandomMizer.GetNextValue(0, 1).ToString();
                        break;
                    case "smallinteger":
                        returnValue = RandomMizer.GetNextValue(1, 255).ToString();
                        break;
                    case "money":
                        returnValue = RandomMizer.GetNextValue(1, 255).ToString();
                        break;
                    case "decimal":
                        returnValue =Convert.ToDecimal(RandomMizer.GetNextValue(1, 255)).ToString();
                        break;
                    case "float":
                    case "double":
                        returnValue = RandomMizer.GetNextValue(1, 10000000).ToString();
                        break;
                    case "int32":
                    case "int":
                    case "integer":
                        returnValue = RandomMizer.GetNextValue(1, 23000).ToString();
                        break;
                    case "xml":
                        returnValue = "null";// string.Format("'<?xml version=\"1.0\" encoding=\"utf-8\" ?><DataLoad cleanDB=\"false\"></DataLoad>'");
                        break;
                    case "datetime":
                        returnValue = DateTimeProcessor.GenerateValue(hintValue.Trim().ToLower());
                        break;
                    default:
                        returnValue = ApplyDefaultStringProcessor(property, hintValue, entityKeyFilename, tableName, dataAccess,currentIteration);
                        break;
                }

            }
            return returnValue;
        }

        protected static string ApplyDefaultStringProcessor(XElement property, string hintValue, string entityKeyFilename, string tableName, DataAccessLayer.DataAccess dataAccess, int currentIteration)
        {
            string[] entries = hintValue.Trim().ToLower().Split("-".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            string returnValue;
            int maxCharacters;
            switch (entries[0].Trim())
            {
                case "title":
                    returnValue = HumanNameGenerator.HumanTitle;
                    break;
                case "surname":
                    returnValue = HumanNameGenerator.HumanName;
                    break;
                case "firstname":
                    returnValue = HumanNameGenerator.HumanName;
                    break;
                case "languagecode":
                    returnValue = HumanNameGenerator.LanguageCode;
                    break;
                case "language":
                    returnValue = HumanNameGenerator.Language;
                    break;
                case "abbrvhumangender":
                    returnValue = HumanNameGenerator.AbbrevatedHumanGender;
                    break;
                case "humangender":
                    returnValue = HumanNameGenerator.HumanGender;
                    break;
                case "telephone":
                    returnValue = TelephoneNumberGenerator.GenerateTelephoneNumber();
                    break;
                case "emailaddress":
                    returnValue = EmailAddressGenerator.GenerateEmailAddress();
                    break;
                case "regex":
                    returnValue = RegexProcessor.GenerateValue(property.ReadAttributeValue(Tokens.RegexPattern));
                    break;
                case "postcode":
                    returnValue = AddressGenerator.Postcode;
                    break;
                case "town":
                    returnValue = AddressGenerator.TownName;
                    break;
                case "addressline1":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    {
                        returnValue = AddressGenerator.Addressline1(maxCharacters);
                    }
                    else
                    {
                        throw new Exception("The value for the addressline1 hint must follow the following pattern addressline1-5 Where the number signifies the maximum string length.");
                    }
                    break;
                case "addressline2":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    {
                        returnValue = AddressGenerator.Addressline2(maxCharacters);
                    }
                    else
                    {
                        throw new Exception("The value for the addressline2 hint must follow the following pattern addressline2-5 Where the number signifies the maximum string length.");
                    }
                    break;
                case "addressline3":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    { returnValue = AddressGenerator.Addressline3(maxCharacters); }
                    else
                    {
                        throw new Exception("The value for the addressline3 hint must follow the following pattern addressline3-5 Where the number signifies the maximum string length.");
                    }
                    break;
                case "country":
                    returnValue = AddressGenerator.CountryName;
                    break;
                case "max":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    {
                        returnValue = StringProcessor.GenerateValue(maxCharacters, IsUpperCaseRequired(entries));
                    }
                    else
                    {
                        throw new Exception("The value for the max hint must follow the following pattern max-5 Where the number signifies the maximum string length.");
                    }
                    break;
                case "username":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    {
                        returnValue = StringProcessor.GenerateUniqueUsername(maxCharacters, entityKeyFilename, tableName, property.ReadAttributeValue(Tokens.PropertyName), IsUpperCaseRequired(entries), dataAccess);
                    }
                    else
                    {
                        throw new Exception("The value for the username hint must follow the following pattern username-5 Where the number signifies the maximum string length.");
                    }
                    break;
                case "incrementpassword":
                    int passwordStartValue;
                    if (entries.Length > 2 && int.TryParse(entries[2], out passwordStartValue))
                    {
                        returnValue = StringProcessor.GeneratePatternedPassword(entries[1], currentIteration, passwordStartValue);
                    }
                    else
                    {
                        throw new Exception("The value for the incrementpassword hint must follow the following pattern incrementpassword-sometext-1 Where the sometext signifies the string to which a number will be appended and 1 indicates the value to start counting from.");
                    }
                    break;
                case "uniqueincrementusername":
                    int usernameStartValue;
                    if (entries.Length > 2 && int.TryParse(entries[2], out usernameStartValue))
                    {
                        returnValue = StringProcessor.GeneratePatternedUsername(entries[1], entityKeyFilename, tableName, property.ReadAttributeValue(Tokens.PropertyName), dataAccess, currentIteration, usernameStartValue);
                    }
                    else
                    {
                        throw new Exception("The value for the uniqueincrementusername hint must follow the following pattern uniqueincrementusername-sometext-1 Where the sometext signifies the string to which a number will be appended and 1 indicates the value to start counting from.");
                    }
                    break;
                case "unique":
                    if (entries.Length > 1 && int.TryParse(entries[1], out maxCharacters))
                    {
                        returnValue = StringProcessor.GenerateUniqueValue(maxCharacters, entityKeyFilename, tableName, property.ReadAttributeValue(Tokens.PropertyName), IsUpperCaseRequired(entries), dataAccess);
                    }
                    else
                    {
                        throw new Exception("The value for the unique hint must follow the following pattern unique-5 Where the number signifies the maximum string length.");
                    }
                    break;
                default:
                    returnValue = property.ReadAttributeValue(Tokens.PropertyName);
                    break;
            }

            return string.Format("'{0}'", returnValue.Replace("'", "''"));
        }

        private static bool IsUpperCaseRequired(string[] entries)
        {
            var upperCase = false;
            if (entries.Length > 2 && entries[2].Trim().ToLower().Equals("uppercase"))
            {
                upperCase = true;
            }
            return upperCase;
        }
    }
}